﻿using System;
using System.Collections.Generic;

namespace BizElements.Core
{
    /// <summary>Entity key binder factory creates <see cref="IEntityKeyBinder"/> objects for provided entities. You may register custom binders.</summary>
    /// <remarks><para>By default, the factory checks if an entity implements <see cref="IEntityKeyBinder"/> interface. 
    /// If not then a default or custom <see cref="IEntityKeyBinder"/> object is created that provides primary key services.</para></remarks>
    public static class EntityKeyBinderFactory
    {
        static readonly Type DefaultKeyBinderClass = typeof(EntityKeyBinder);
        static readonly Dictionary<string, Type> KeyBinderMap = new Dictionary<string, Type>();

        /// <summary>Registers custom key binder for entities mapped to the specified table/view name.</summary>
        /// <typeparam name="T">A class that implements <see cref="IEntityKeyBinder"/> interface and has a default/parameterless constructor.</typeparam>
        /// <param name="tableName">Table/view name.</param>
        public static void RegisterKeyBinder<T>(string tableName)
            where T : class, IEntityKeyBinder, new()
        {
            KeyBinderMap[tableName] = typeof(T);
        }

        /// <summary>Gets binder object that provides key binding services for the specified entity.</summary>
        /// <param name="entity">Entity. If it implements IEntityKeyBinder then it is returned by the method.</param>
        /// <returns>Key binder.</returns>
        public static IEntityKeyBinder GetKeyBinder(IEntity entity)
        {
            // Entity may handle binding on its own. E.g. classes which derive from EntityModelBase.
            IEntityKeyBinder binder = entity as IEntityKeyBinder;
            if (binder != null)
                return binder;

            Type binderClass;
            KeyBinderMap.TryGetValue(entity.Table.TableName, out binderClass);
            if (binderClass == null)
                binderClass = DefaultKeyBinderClass;

            binder = (IEntityKeyBinder)Activator.CreateInstance(binderClass);
            binder.EntityWithKey = entity;
            return binder;
        }
    }
}
